package dk.dashboardFP.panels.displayPanel {
	import dk.dashboardFP.dfpLogger.DFPLogger;
	import dk.dashboardFP.panels.displayPanel.core.DisplayEditorCoreEvent;
	import dk.dashboardFP.panels.displayPanel.core.EditorItem;
	import dk.dashboardFP.panels.introspectionPanel.DCIntrospectionNode;
	import dk.dashboardFP.panels.introspectionPanel.IntrospectionNodeView;
	import dk.dashboardFP.panels.introspectionPanel.IntrospectionNodeViewEvent;
	import dk.dashboardFP.utils.DisplayChainTools;
	import dk.dashboardFP.utils.FProxy;
	import dk.dashboardFP.utils.keyListener.KeyListener;

	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Stage;
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	import flash.utils.Timer;

	/**
	 * @author josef
	 */
	public class DisplayEditorControl extends EventDispatcher {

		private var _oDisplayPanel : DisplayPanel;
		private var _doStage : Stage;
		private var _nMouseOverRefreshDelay : Number = 5;
		private var _oMouseTime : Timer;
		private var _doMousedOver : DisplayObject;
		private var _bInSelectionMode : Boolean;
		private var _nSelectionToggleTime : Number = 150;
		private var _oSelectionTimer : Timer;
		private var _bInListSelection : Boolean;
		private var _doSelectionList : SelectionList;
		private var _sCurrentDisplayEditorMode : String;
		private var _sLastMode : String;
		private var _bEnabled : Boolean = false;
		private var _markedFromIntrospection : DisplayObject;
		private var _isInQuickMessure : Boolean= false;
		private var _quickMessureTarget : EditorItem;
		private var _currentMessurePoint : DisplayObject;

		public function DisplayEditorControl(oDisplayPanel : DisplayPanel) {
			_oDisplayPanel = oDisplayPanel;
			super();
			setup();
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// setup
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function setup() : void {
			
			//:::::::
			// stage ref 
			_doStage = _oDisplayPanel.doDashboard.doStage;
			
			//:::::::
			// setups
			setupMouseOverListener();
			setupSelectionHandler();
			
			//:::::::
			// init 
			_sCurrentDisplayEditorMode = DisplayEditorModes.MOVE;
			setMode(DisplayEditorModes.MOVE);
			
			//:::::::
			// register for core 
			_oDisplayPanel.oDisplayEditorCore.registerController(this);
			_oDisplayPanel.oGlobalViewControl.registerController(this);
			
			// quick messure 
			setupQuickMessure();
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// mode control
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		//:::::::
		// temp pan 
		private function tempPanOut() : void {
			setMode(_sLastMode);	
		}

		private function tempPanIn() : void {
			_sLastMode = _sCurrentDisplayEditorMode;
			setMode(DisplayEditorModes.PAN);
		}

		//:::::::
		// set mode 
		public function setMode(sEditorMode : String) : void {
			
			if (sEditorMode == _sCurrentDisplayEditorMode) return;
			
			//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
			// switch off old mode
			//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
			switch(_sCurrentDisplayEditorMode) {
				
				case DisplayEditorModes.NAVIGATION:
					break;
				case DisplayEditorModes.SELECT:
				
					_bInSelectionMode = false;
					_oDisplayPanel.doDashboard.doStage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);

					_oMouseTime.reset();
					clearOver();
					
					break;
				case DisplayEditorModes.MOVE:
					_oDisplayPanel.oDragController.disableDrag();
					break;
				case DisplayEditorModes.PAN:
					_oDisplayPanel.oDragController.disableDrag();
					break;
			}
			
			
			//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
			// switch on new mode
			//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

			
			switch(sEditorMode) {
				case DisplayEditorModes.NAVIGATION:
					break;
				case DisplayEditorModes.SELECT:
									
					_bInSelectionMode = true;
					_doStage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false, 0, true);
				
					evaluateMouseOver();
					
					break;
				case DisplayEditorModes.MOVE:
					_oDisplayPanel.oDragController.enableDrag();
					break;
				case DisplayEditorModes.PAN:
					_oDisplayPanel.oDragController.enableDrag();
					break;
			}
			
			_sCurrentDisplayEditorMode = sEditorMode;
			dispatchEvent(new DisplayEditorControlEvent(DisplayEditorControlEvent.CHANGED_MODE));
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// enable / disable
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public function disable() : void {
			disableSelectionHandlers();
		}

		public function enable() : void {
			enableSelectionHandlers();
		}

		private function enableSelectionHandlers() : void {
			
			//:::::::
			// listen  
			_oDisplayPanel.doDashboard.doPanelHolder.addEventListener(IntrospectionNodeViewEvent.DISPLAY_OBJECT_MARK, onMarkRequestedFromIntrospection);
			_oDisplayPanel.doDashboard.doPanelHolder.addEventListener(IntrospectionNodeViewEvent.DISPLAY_OBJECT_MARK_REMOVE, onMarkRemoveRequestedFromIntrospection);
			_oDisplayPanel.doDashboard.doPanelHolder.addEventListener(IntrospectionNodeViewEvent.DISPLAY_OBJECT_SELECT, onSelectRequestedFromIntrospection);
			
			//:::::::
			// key down 
			KeyListener.getInstance().addKeyDown(Keyboard.CONTROL, setSelectionMode);
			KeyListener.getInstance().addKeyDown(15, setSelectionMode);

			//:::::::
			// key up 
			KeyListener.getInstance().addKeyUp(Keyboard.CONTROL, disableSelecitionMode);
			KeyListener.getInstance().addKeyUp(15, disableSelecitionMode);
			
			//:::::::
			// register keys 
			//KeyListener.oInstance.addKeyDown(65, FProxy.create(this, setMode, DisplayEditorModes.NAVIGATION));
			KeyListener.getInstance().addKeyDown(86, FProxy.create(this, setMode, DisplayEditorModes.MOVE));
			KeyListener.getInstance().addKeyDown(80, FProxy.create(this, setMode, DisplayEditorModes.PAN));
			
			//:::::::
			// space for pan 
			KeyListener.getInstance().addKeyDown(32, tempPanIn);
			KeyListener.getInstance().addKeyUp(32, tempPanOut);
			
			//:::::::
			// hide selection and deselect
			KeyListener.getInstance().addKeyDown(87, toggleSelectionMarkVisible);
			KeyListener.getInstance().addKeyDown(68, deselectCurrent);
			
			//:::::::
			// mouse 
			_doStage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			
			_bEnabled = true;
			dispatchEvent(new DisplayEditorControlEvent(DisplayEditorControlEvent.TOGGLE_ENABLED));
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// introspection  reequest
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function onSelectRequestedFromIntrospection(event : IntrospectionNodeViewEvent) : void {
			
			//:::::::
			// set selection 
			_oDisplayPanel.oDisplayEditorCore.select(_doMousedOver, (event.data != null ? event.data : false));
		}

		private function onMarkRemoveRequestedFromIntrospection(event : IntrospectionNodeViewEvent) : void {
			_markedFromIntrospection = null;
			setMousedOver(null);
		}

		private function onMarkRequestedFromIntrospection(event : IntrospectionNodeViewEvent) : void {
			if (sCurrentDisplayEditorMode == DisplayEditorModes.SELECT) {
				_markedFromIntrospection = (DCIntrospectionNode(IntrospectionNodeView(event.target).introspectionNode).displayObjectRefrence);
			}
		}

		//:::::::
		// control 

		private function deselectCurrent() : void {
			_oDisplayPanel.oDisplayEditorCore.deselectAll();
		}

		private function toggleSelectionMarkVisible() : void {
			_oDisplayPanel.oDisplayEditorCore.toggleSelectionMarkVisible();
		}

		private function disableSelectionHandlers() : void {
			
			//:::::::
			// listen  
			_oDisplayPanel.doDashboard.doPanelHolder.removeEventListener(IntrospectionNodeViewEvent.DISPLAY_OBJECT_MARK, onMarkRequestedFromIntrospection);
			_oDisplayPanel.doDashboard.doPanelHolder.removeEventListener(IntrospectionNodeViewEvent.DISPLAY_OBJECT_MARK_REMOVE, onMarkRemoveRequestedFromIntrospection);
			_oDisplayPanel.doDashboard.doPanelHolder.removeEventListener(IntrospectionNodeViewEvent.DISPLAY_OBJECT_SELECT, onSelectRequestedFromIntrospection);
			
			//:::::::
			// stop drag control 
			_oDisplayPanel.oDragController.disableDrag();
			
			//:::::::
			// deselect all 
			_oDisplayPanel.oDisplayEditorCore.deselectAll();
			clearOver();
			
			//:::::::
			// key down 
			KeyListener.getInstance().removeKeyDown(Keyboard.CONTROL, setSelectionMode);
			KeyListener.getInstance().removeKeyDown(15, setSelectionMode);

			//:::::::
			// key up 
			KeyListener.getInstance().removeKeyUp(Keyboard.CONTROL, disableSelecitionMode);
			KeyListener.getInstance().removeKeyUp(15, disableSelecitionMode);
			
			//:::::::
			// register keys 
			//KeyListener.oInstance.removeKeyDown(65);
			KeyListener.getInstance().removeKeyDown(86);
			KeyListener.getInstance().removeKeyDown(80);
			
			KeyListener.getInstance().removeKeyDown(32, tempPanIn);
			KeyListener.getInstance().removeKeyUp(32, tempPanOut);
			
			
			//:::::::
			// hide selection and deselect
			KeyListener.getInstance().removeKeyDown(87);
			KeyListener.getInstance().removeKeyDown(68);
			
			//:::::::
			// mouse 
			_doStage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			
			//:::::::
			// check 
			if (_bInSelectionMode) {
				disableSelecitionMode();
			}
			
			_bEnabled = false;
			dispatchEvent(new DisplayEditorControlEvent(DisplayEditorControlEvent.TOGGLE_ENABLED));
		}

		private function disableSelecitionMode() : void {
			if (_sLastMode) {
				setMode(_sLastMode);
			} else {
				setMode(DisplayEditorModes.NAVIGATION);
			}
		}

		private function setSelectionMode() : void {
			_sLastMode = _sCurrentDisplayEditorMode;
			setMode(DisplayEditorModes.SELECT);
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// selection
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function setupSelectionHandler() : void {
			
			//:::::::
			// selection timer
			_oSelectionTimer = new Timer(_nSelectionToggleTime, 1);
			_oSelectionTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onSelectionTimer);
		}

		private function onSelectionTimer(event : TimerEvent) : void {
			switchToListSelection();
		}

		private function switchToListSelection() : void {
			
			//:::::::
			// escape if no object marked 
			if (!_doMousedOver) return;
			_bInListSelection = true;
			
			//:::::::
			// launc list 
			_doSelectionList = new SelectionList(_doMousedOver);
			_oDisplayPanel.doDashboard.oContextPanelHandler.addContextPanel(_doSelectionList);
			
			_doSelectionList.addEventListener(SelectionListEvent.MARK_OBJECT, onMarkObjectFromList, false, 0, true);
		}

		private function onMarkObjectFromList(event : SelectionListEvent) : void {
			setMousedOver(event.doObject);
		}

		private function onMouseDown(event : MouseEvent) : void {
			if(!DisplayChainTools.get_bIsChildOf(DisplayObject(event.target), _oDisplayPanel.doDashboard.doPanelHolder)) {
				startSelection();
			}
		}

		private function startSelection() : void {
			
			//:::::::
			// set timer 
			_oSelectionTimer.reset();
			_oSelectionTimer.start();
			
			//:::::::
			// register upevent 
			_doStage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		}

		private function onMouseUp(event : MouseEvent) : void {
			endSelection(event.shiftKey);
		}

		private function endSelection(bAddToSelection : Boolean) : void {
			
			//:::::::
			// selection list 
			if (_bInListSelection) {
				_oDisplayPanel.doDashboard.oContextPanelHandler.removeContextPanel(_doSelectionList);
			}
			
			_oSelectionTimer.reset();
			_doStage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
			
			_bInListSelection = false;
			
			//:::::::
			// set selection 
			_oDisplayPanel.oDisplayEditorCore.select(_doMousedOver, bAddToSelection);
		}
		
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// quick messure
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		
		private function setupQuickMessure() : void {
			_oDisplayPanel.oDisplayEditorCore.addEventListener(DisplayEditorCoreEvent.CHANGE_SELECTION, onChangeSelection, false, 0, true);
		}

		private function onChangeSelection(event : DisplayEditorCoreEvent) : void {
			if (_oDisplayPanel.oDisplayEditorCore.hasSingleSelection && !_isInQuickMessure) {
				enableQuickMessure(event.oEI);
			} else if (_isInQuickMessure) {
				disableQuickMessure();
			}
		}

		private function disableQuickMessure() : void {
			_isInQuickMessure=false;
			_doStage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMessureMove);
		}

		private function enableQuickMessure(ei:EditorItem) : void {
			_isInQuickMessure=true;
			_quickMessureTarget=ei;
			
			DFPLogger.log("look for :: " + _quickMessureTarget.doTarget.parent);
			_doStage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMessureMove, false, 0, true);
		}

		private function onMouseMessureMove(event : MouseEvent) : void {
			
			
			var a_doUnderPoint : Array = _doStage.getObjectsUnderPoint(new Point(_doStage.mouseX, _doStage.mouseY));
			var brotherObject:DisplayObject;
			
			var topObject:DisplayObject=a_doUnderPoint[a_doUnderPoint.length-1];
			 
			if (DisplayChainTools.get_bIsChildOf(topObject, _oDisplayPanel.doDashboard.sprOverlayHolder)) {
				
			} else {
				var parent:DisplayObjectContainer=topObject.parent;
				while(parent && parent!=_doStage) {
					brotherObject = parent;
					if (parent.parent == _quickMessureTarget.doTarget.parent)  {
						if (brotherObject!=_currentMessurePoint) {
							setMessurePoint(brotherObject);
						}
					}
					parent = parent.parent;
				}
			}
		}

		private function setMessurePoint(pointTarget : DisplayObject) : void {
			DFPLogger.log("Set messure point :: " + pointTarget);
			_currentMessurePoint = pointTarget;
			
			_quickMessureTarget.showMessurements(pointTarget);
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// mouse over
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		//:::::::
		// control 

		private function setupMouseOverListener() : void {
			_oMouseTime = new Timer(_nMouseOverRefreshDelay, 1);
			_oMouseTime.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete, false, 0, false);
		}

		private function onTimerComplete(event : TimerEvent) : void {
			evaluateMouseOver();
		}

		private function evaluateMouseOver() : void {
			
			//:::::::
			// cancel if in list selection 
			if (_bInListSelection || _sCurrentDisplayEditorMode != DisplayEditorModes.SELECT) return;

			var a_doUnderPoint : Array = _doStage.getObjectsUnderPoint(new Point(_doStage.mouseX, _doStage.mouseY));
			var a_doAllowedObjects : Array = [];
			
			//:::::::
			// remove panel items 
			for (var i : Number = 0;i < a_doUnderPoint.length;i++) {
				if (DisplayChainTools.get_bIsChildOf(a_doUnderPoint[i], _oDisplayPanel.doDashboard.sprOverlayHolder)) {
				} else {
					a_doAllowedObjects[a_doAllowedObjects.length] = a_doUnderPoint[i];
				}
			}
			
			if (a_doAllowedObjects.length != 0) {
				setMousedOver(a_doAllowedObjects[a_doAllowedObjects.length - 1]);
			} else {
				setMousedOver(null);
			}
		}

		private function setMousedOver(doMousedOver : DisplayObject) : void {
			
			if (_markedFromIntrospection) {
				if ((_markedFromIntrospection != _doMousedOver)) {
					_doMousedOver = _markedFromIntrospection;
					_oDisplayPanel.oDisplayOverlayHandler.markPointerObject(_doMousedOver);
				}
				return;
			}
			
			if (doMousedOver == _doMousedOver) {
				return;
			}
			
			_doMousedOver = doMousedOver;
			_oDisplayPanel.oDisplayOverlayHandler.markPointerObject(_doMousedOver);
		}

		private function clearOver() : void {

			if (_markedFromIntrospection) return;

			_doMousedOver = null;
			_oDisplayPanel.oDisplayOverlayHandler.markPointerObject(null);
		}

		private function onMouseMove(event : MouseEvent) : void {
			if (_oMouseTime.running) {
				_oMouseTime.reset();
			}
			_oMouseTime.start();
		}

		public function get sCurrentDisplayEditorMode() : String {
			return _sCurrentDisplayEditorMode;
		}

		public function get bEnabled() : Boolean {
			return _bEnabled;
		}
	}
}
